package src

import (
	"pp/comm"
)

/*
打地鼠
*/

type (
	//基础方案
	dishuPower struct {
		Ratio  float64 //倍率
		Weight uint32  //权重 每一档都是独立的
	}

	//胜率控制
	dishuConfig struct {
		par_x float64 //平衡点
		par_a uint64
	}

	user struct {
		id uint32

		win  uint64
		cost uint64

		rate1 uint32 //方案1次数
		rate2 uint32
	}
)

var (
	//放水
	dishuPowerConf1 = []*dishuPower{
		//{Ratio: 0, Weight: 1}, //没中的要配置
		{Ratio: 1.23, Weight: 75},
		{Ratio: 1.54, Weight: 66},
		{Ratio: 1.93, Weight: 50},
		{Ratio: 2.41, Weight: 50},
		{Ratio: 4.02, Weight: 39},
		{Ratio: 6.71, Weight: 35},
		{Ratio: 11.18, Weight: 31},
		{Ratio: 27.97, Weight: 31},
		{Ratio: 69.93, Weight: 11},
		{Ratio: 349.68, Weight: 11},
	}
	//抽水
	dishuPowerConf2 = []*dishuPower{
		//{Ratio: 0, Weight: 1}, //没中的要配置
		{Ratio: 1.23, Weight: 66},
		{Ratio: 1.54, Weight: 49},
		{Ratio: 1.93, Weight: 48},
		{Ratio: 2.41, Weight: 37},
		{Ratio: 4.02, Weight: 35},
		{Ratio: 6.71, Weight: 35},
		{Ratio: 11.18, Weight: 31},
		{Ratio: 27.97, Weight: 31},
		{Ratio: 69.93, Weight: 11},
		{Ratio: 349.68, Weight: 11},
	}
	//DishuPowerDatas []*dishuPower
	AllWeight int

	dishuConf = &dishuConfig{
		par_x: 0.078,
		par_a: 8000,
	}

	mapRewardLv = map[int]int{} //中奖挡位统计

	Users []*user //角色
)

func (c *user) reset() {
	c.win = 0
	c.cost = 0
	c.rate1 = 0
	c.rate2 = 0
}

func (c *user) showWin() {
	comm.Printf("------ uid:%+v, 方案1/2:%+v/%+v, win:%+v, cost:%+v, 胜率:%.2f\n",
		c.id, c.rate1, c.rate2, c.win, c.cost, float64(c.win)/float64(c.cost)*100)
}

//--------------------------------------------------------------------------------------

func Dadishu() {
	onInit()
	calcTheory()
	dishuTest()
}

func dishuTest() {
	const N = 50000
	var (
		bet   = 9000
		rates = []int{1, 2, 0} //方案集
	)
	for _, v := range rates {
		comm.Printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>> test dadishu, 方案:%+v\n", rateDesc(v))
		for _, u := range Users {
			for i := 0; i < N; i++ {
				ratio, n := la(u, v)
				u.win += uint64(ratio * float64(bet))
				u.cost += uint64(bet * n)
			}
			u.showWin()
			u.reset() //重置
		}
	}

	comm.Printf("dadishu, 中奖档次统计:%+v\n", mapRewardLv)
}

func onInit() {
	for i := 0; i < 10; i++ {
		Users = append(Users, &user{
			id: uint32(i) + 1000,
		})
	}
	/* var sumR float64
	for _, v := range dishuPowerConf {
		sumR += v.Ratio
		AllWeight += int(v.Weight)
		DishuPowerDatas = append(DishuPowerDatas, &dishuPower{
			Ratio:  v.Ratio, //sumR,
			Weight: v.Weight,
		})
	}
	fmt.Printf("dadishu power datas:%+v, allweight:%+v\n", DishuPowerDatas, AllWeight) */
}

func rateDesc(r int) string {
	if r == 1 {
		return "放水"
	} else if r == 2 {
		return "抽水"
	} else if r == 0 {
		return "综合"
	} else {
		panic("未知方案")
	}
}

func getDishuPower(r int) []*dishuPower {
	if r == 1 {
		return dishuPowerConf1
	} else if r == 2 {
		return dishuPowerConf2
	} else {
		return nil
	}
}

//---------------------------------------------------------------------------------------------------------

// 理论计算
func calcTheory() {
	var (
		rates = []int{1, 2}
	)
	for _, v := range rates {
		calcTheoryRate(v)
	}
}

func calcTheoryRate(r int) {
	var (
		win  float64 //总赢取(按消耗=1)
		cost float64
		bet  int     = 1
		pro  float64 = 1 //权重迭代

		dpConf []*dishuPower = getDishuPower(r)
	)
	cost += float64(bet) //第一轮必消耗 之后的用概率计算
	for k, v := range dpConf {
		pro *= float64(v.Weight) / 100
		win += pro * v.Ratio * float64(bet)
		if k < len(dpConf)-1 {
			cost += float64(bet) * pro //下一轮的期望值
		}
	}
	comm.Printf("dadishu, 理论计算 方案:%+v Theory winr:%.2f\n", rateDesc(r), win*100/cost)
}

//---------------------------------------------------------------------------------------------------------

func selectRate(u *user, r int) int {
	if r == 0 {
		if float64(u.win)*(1+dishuConf.par_x)-float64(u.cost) > float64(u.cost)/100+float64(dishuConf.par_a) {
			r = 2
		} else {
			r = 1
		}
	}

	if r == 1 {
		u.rate1++
	} else if r == 2 {
		u.rate2++
	}
	return r
}

// 一轮=可以打多少层
func la(u *user, r int) (float64, int) {
	var (
		ret    []*dishuPower
		sumR   float64
		dpConf []*dishuPower
	)

	r = selectRate(u, r) //实际的
	dpConf = getDishuPower(r)
	for k, v := range dpConf {
		if laI(v) {
			ret = append(ret, v)
			mapRewardLv[k+1]++
		} else {
			break
		}
	}
	if len(ret) >= 9 {
		//comm.Println(">>>>>>>>>>>>>>>>>>>> lucky:", len(ret))
	}
	for _, v := range ret {
		sumR += v.Ratio
	}
	return sumR, comm.Min(len(ret)+1, len(dpConf))
}

func laI(dp *dishuPower) bool {
	pro := comm.Random(0, 100) //每一档都是独立的权重 按100算 AllWeight
	return pro < int(dp.Weight)
}

/* func laI(i int) *dishuPower {
	var (
		sumR uint32
		pro  = comm.Random(0, AllWeight)
	)
	for _, v := range DishuPowerDatas {
		sumR += v.Weight
		if pro < int(sumR) {
			return v
		}
	}
	panic("rand win, dishu power conf err")
	return nil
} */
